#include <libdswsession/dswavfwdsession.h>

static const ST_P2PMSG_T m_trans_vmsg[] = {
	{"MSG_PUA_START_STREAM_RESP", NULL, CDswavfwdsession::cbPUAStartStreamResp},
	{"MSG_PUG_STOP_STREAM_RESP", NULL, CDswavfwdsession::cbPUGStopStreamResp},
	{"END","", NULL},
};

CDswavfwdsession::CDswavfwdsession(LPST_ENV_T pEnv, char * pHost, int nPort, LPST_TRANS_REQ_T pFwdInfo)
: CDswavsession(pEnv, pHost, nPort)
, m_nSessionType(MISSION_FWD)
, m_nWaitSendFrameID(0)
{
	LOG4CPLUS_DEBUG(log_dsw, "Create CDswavfwdsession class!");
	memcpy(&m_nFwdInfo, pFwdInfo, sizeof(m_nFwdInfo));
	sprintf(m_sKey, "%s_%d_%d", FWD_KEY, pFwdInfo->nCh, pFwdInfo->bLocal);
	strcpy(m_sPucID, pFwdInfo->sPUCId);
	m_sAddStreamBuf[0] = '\0';
	pthread_mutex_init(&m_nAddStreamBuf_Lock, NULL);
}

CDswavfwdsession::~CDswavfwdsession()
{
	ST_SESSION_NOTIFY_T nNotify;
	nNotify.pKey = m_sKey;
	SendMessage(PMSG_SET_AVSESSION_REMOVE, (void*)&nNotify);
	pthread_mutex_destroy(&m_nAddStreamBuf_Lock);
	LOG4CPLUS_DEBUG(log_dsw, "Destroy CDswavfwdsession class!");
}

void CDswavfwdsession::MakePUAStartStreamReq(CMarkup & xml, char* pP2PPucId)
{
	ST_DEVICE_BASE_T nBasicParam;
	SendMessage(PMSG_GET_DEVICE_BASE_PARAM, (void*)&nBasicParam);
	xml.SetDoc(XMLFLAG);
	xml.AddElem("Message");
	xml.SetAttrib("Version", XMLVER_1);
	xml.IntoElem();
		xml.AddElem("MessageType", "MSG_PUA_START_STREAM_REQ");
	xml.OutOfElem();
	xml.AddElem("PUC_ID", pP2PPucId);
	xml.AddElem("PUA_ID", nBasicParam.devid);
	xml.AddElem("PUG_ID", m_nFwdInfo.sPUGId);
	xml.AddElem("EX");
	xml.IntoElem();
		xml.AddElem("CID", m_nFwdInfo.sCallId);
		if (strcmp(m_nFwdInfo.sType, LIVE_VIDEO_REQ) == 0){
			xml.AddElem("CHN", m_nFwdInfo.nCh);
			xml.AddAttrib("STREAM", m_nFwdInfo.nStream);
			xml.AddAttrib("LOCAL", m_nFwdInfo.bLocal);
		}
		else if (strcmp(m_nFwdInfo.sType, REC_PLAYBACK_REQ) == 0){
			xml.AddElem("CHN", m_nFwdInfo.nCh);
			xml.AddAttrib("LOCAL", m_nFwdInfo.bLocal);
			xml.AddElem("RECFILE", m_nFwdInfo.sFileName);
			xml.AddAttrib("SPEED", m_nFwdInfo.nSpeed);
		}
		else if (strcmp(m_nFwdInfo.sType, REC_DOWNLOAD_REQ) == 0)
			xml.AddElem("RECFILE", m_nFwdInfo.sFileName);
	xml.OutOfElem();
}

void CDswavfwdsession::OnConnect(struct bufferevent *bev, short events)
{
	LOG4CPLUS_DEBUG(log_dsw, "Connect ax session [ " << m_sHost << ":" << m_nPort << " ] , session type: " << m_nSessionType << " !");
	m_nWantReadLen = AV_SESSION_HEADSIZE;
	CDswtcpclient_base::OnConnect(bev, events);
	CMarkup xml;
	MakePUAStartStreamReq(xml, m_nFwdInfo.sPUCId);
	SendMsg((char*)xml.GetDoc().c_str());
	struct timeval tv = {30, 0};
	bufferevent_set_timeouts(m_pBev, &tv, NULL);
}

bool CDswavfwdsession::ProcessTxtMsg_V1(char* pMsg, int nLen, struct evbuffer *outbuf)
{
	CMarkup xml;
	xml.SetDoc(pMsg);
	if (!xml.FindElem("Message"))
		return false;
	xml.IntoElem();
		if (!xml.FindElem("DSW_HEADER"))
			return false;
		xml.IntoElem();
			if (!xml.FindElem("MessageType"))
				return false;
			char sMsg[128];
			strcpy(sMsg, xml.GetData().c_str());
			LPST_P2PMSG_T pPos = (LPST_P2PMSG_T)m_trans_vmsg;
			while(strcmp(pPos->sMsgReq, "END") != 0){
				if ((strcmp(pPos->sMsgReq, sMsg) == 0) && (pPos->pP2PFunc != NULL)){
					return pPos->pP2PFunc(NULL, pMsg, pPos->sMsgIDResp, this);
					break;
				}
				pPos++;
			}
		xml.OutOfElem();
	xml.OutOfElem();
	return false;
}

bool CDswavfwdsession::PUAStartStreamResp(char* pCId, void* pMsgReq, const char* pMsgResp)
{
	ST_SESSION_NOTIFY_T nNotify;
	CMarkup xml;

	xml.SetDoc((char*)pMsgReq);
	if (!xml.FindElem("Message"))
		return false;
	xml.IntoElem();
	if (!xml.FindElem("DSW_RESULT"))
		return false;
	xml.IntoElem();
	if (!xml.FindElem("ErrorCode"))
		return false;
	if (atoi(xml.GetData().c_str()) != 0)
		return false;

	nNotify.pKey = m_sKey;
	nNotify.bRet = false;
	nNotify.pClass = (void*)this;
	SendMessage(PMSG_SET_AVSESSION_ADD, (void*)&nNotify);

	if (nNotify.bRet){
		if (strcmp(m_nFwdInfo.sType, LIVE_VIDEO_REQ) == 0){
			if ((m_nFwdInfo.nStream >= MAX_V_BITSTREAM_NUM) || (m_nFwdInfo.nStream < 0))
				m_nFwdInfo.nStream = MAIN_STREAM;
			if ((m_nFwdInfo.nCh >= MAX_VIDEO_CHANNEL) || (m_nFwdInfo.nCh < 0))
				m_nFwdInfo.nCh = 0;
			StartAVStream(m_nFwdInfo.nCh, m_nFwdInfo.nStream, m_nFwdInfo.bLocal);
		}
		else if (strcmp(m_nFwdInfo.sType, REC_DOWNLOAD_REQ) == 0){
			StartDownloadStream(m_nFwdInfo.sFileName, true);
		}
		else if (strcmp(m_nFwdInfo.sType, REC_PLAYBACK_REQ) == 0){
			StartRecPlayStream(m_nFwdInfo.nCh, m_nFwdInfo.nStream, m_nFwdInfo.sFileName, m_nFwdInfo.nSpeed, m_nFwdInfo.bLocal, m_nFwdInfo.sZtime);
		}
		else{
			LOG4CPLUS_ERROR(log_dsw, "Invalid av session type! [ " << m_nFwdInfo.sType << " ]");
			return false;
		}
	}
	return true;
}

bool CDswavfwdsession::PUGStopStreamResp(char* pCId, void* pMsgReq, const char* pMsgResp)
{
	CMarkup xml;
	xml.SetDoc((char*)pMsgReq);
	
	ST_SESSION_NOTIFY_T nNotify;
	nNotify.pKey = m_sKey;
	SendMessage(PMSG_SET_AVSESSION_REMOVE, (void*)&nNotify);
	return true;
}

void CDswavfwdsession::AddNewTransOrder(char* pP2PPucId)
{
	CMarkup xml;
	MakePUAStartStreamReq(xml, pP2PPucId);
	MUTEX_LOCK(&m_nAddStreamBuf_Lock);
	strcpy(m_sAddStreamBuf, (char*)xml.GetDoc().c_str());
	MUTEX_UNLOCK(&m_nAddStreamBuf_Lock);
}

void CDswavfwdsession::ProcessExCmd()
{
	MUTEX_LOCK(&m_nAddStreamBuf_Lock);
	if (strlen(m_sAddStreamBuf) > 0){
		SendMsg(m_sAddStreamBuf);
		m_sAddStreamBuf[0] = '\0';
	}
	MUTEX_UNLOCK(&m_nAddStreamBuf_Lock);
}

void CDswavfwdsession::SendMsg_Ex(char * pMsg)
{
	char sPacketHead[16];
	TcpStreamHead_M nMsgHead;
	int nPacketSize;

	memcpy(nMsgHead.sign, LIVE_M_FLAG, LIVE_M_FLAG_SIZE);
	nMsgHead.nLen = strlen(pMsg);

	nPacketSize = TcpStreamHead_M_HEADSIZE + nMsgHead.nLen;

	sPacketHead[0] = MEDIA_FLAG;
	memcpy(&(sPacketHead[1]), &nPacketSize, sizeof(int));

	evbuffer_add(bufferevent_get_output(m_pBev), sPacketHead, AV_SESSION_HEADSIZE);
	evbuffer_add(bufferevent_get_output(m_pBev), &nMsgHead, TcpStreamHead_M_HEADSIZE);
	evbuffer_add(bufferevent_get_output(m_pBev), pMsg, nMsgHead.nLen);
	
	bufferevent_flush(m_pBev, EV_WRITE, BEV_FLUSH);
}

void CDswavfwdsession::Process_ACK_Wait(char * pMsg)
{
	CMarkup xml;

	xml.SetDoc((char*)pMsg);
	if(xml.FindElem("Message")){
		xml.IntoElem();
		if (xml.FindElem("ACT_WAIT"))
			m_nWaitSendFrameID += atoi(xml.GetAttrib("CNT").c_str());
		else
			m_nWaitSendFrameID = 0;
		xml.OutOfElem();
	}
}

bool CDswavfwdsession::NeedWaitTransFile(int nCurrentFrameID)
{
	if (m_nWaitSendFrameID < 0)
		return false;
	if (nCurrentFrameID < m_nWaitSendFrameID)
		return false;
	return true;
}


